/******************************************************************************
 *      Mestrado em Ciência da Computação - UFMS
 *		Redes de Computadores - Prof. Dr. Ronaldo Alves Ferreira
 *		Alunos: Geraldo Landre, Marcel Tolentino, Vinícius Bueno
 *****************************************************************************/
/* tcpacked.c - tcpacked */

#include "tcpfms.h"
#include "tcb.h"
#include "tcp.h"

/*------------------------------------------------------------------------
 *  tcpacked - handle in-bound ACKs and do round trip estimates
 *------------------------------------------------------------------------
 */
int tcpacked(struct tcb *ptcb, struct udp* pudp)
{
    // struct ip *pip = (struct ip *)pep->ep_data;
    struct	tcp	*ptcp = (struct tcp*)(pudp->udp_data);
    int	acked;
    int cacked;
  //  STATWORD ps;

    if(!(ptcp->tcp_code & TCPF_ACK))
	return SYSERR;
    
    acked = ptcp->tcp_ack - ptcb->tcb_suna;
    cacked = 0;
    
    if(acked <= 0)
        return 0;	/* duplicate ACK */
    
    if(SEQCMP(ptcp->tcp_ack, ptcb->tcb_snext) > 0)
    {
        if(ptcb->tcb_state == TCPS_SYNRCVD)
            return tcpreset(pudp);
        else
            return tcpackit(ptcb, pudp);
    }
    tcprtt(ptcb);
    ptcb->tcb_suna = ptcp->tcp_ack;
    
    if(acked && ptcb->tcb_code & TCPF_SYN) 
    {
        acked--;
        cacked++;
        ptcb->tcb_code &= ~TCPF_SYN;
        ptcb->tcb_flags &= ~TCBF_FIRSTSEND;
    }
    if((ptcb->tcb_code & TCPF_FIN) && SEQCMP(ptcp->tcp_ack, ptcb->tcb_snext) == 0) 
    {
        acked--;
        cacked++;
        ptcb->tcb_code &= ~TCPF_FIN;
        ptcb->tcb_flags &= ~TCBF_SNDFIN;
    }
    if((ptcb->tcb_flags & TCBF_SUPOK) && SEQCMP(ptcp->tcp_ack, ptcb->tcb_supseq) >= 0)
        ptcb->tcb_flags &= ~TCBF_SUPOK;
    
    ptcb->tcb_sbstart = (ptcb->tcb_sbstart+acked) % ptcb->tcb_sbsize;
    ptcb->tcb_sbcount -= acked;
    if(acked) 
    {
        int count;
        sem_getvalue(&(ptcb->tcb_ssema), &count);
      //  disable(ps);
        if(count <= 0)
            sem_post(&(ptcb->tcb_ssema));
      //  restore(ps);
    }
    tcpostate(ptcb, acked+cacked);
    return acked;
}
